home *** CD-ROM | disk | FTP | other *** search
/ PD ROM 1 / PD ROM Volume I - Macintosh Software from BMUG (1988).iso / Stacks / Updates⁄New / TEXAS for BMUG / C progs / TEXAS XFCNs ƒ / jumpKeyXFCN.1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-12-11  |  5.4 KB  |  263 lines  |  [TEXT/KAHL]

  1. /* HyperCard XFCN that takes a target string and returns the key record
  2.  * number just above it in the (already opened) key file F ... called as:
  3.  *    jumpKey ( S, M, F)
  4.  * where S is the string, M is the maximum key_rec_number (0-based, so
  5.  * thus it's one less than the total number of distinct words in the file),
  6.  * and F is a refNum value returned by the XFCN openFile().
  7.  *
  8.  * The results are returned as a 0-terminated string consisting of the
  9.  * key record number (in ASCII) at or just before the input string.
  10.  *
  11.  * If there has been a mistake, a null string is returned and the function
  12.  * also emits a beep....
  13.  *
  14.  * The function works by taking the input string, turning any lower-case
  15.  * letters into capitals, and then does a binary search on the key file.
  16.  *
  17.  * The external function is stored as XFCN number 851, named "jumpKey"....
  18.  *
  19.  * The key file must in the standard ^z browser format as created
  20.  * by qndxr, etc....
  21.  *
  22.  * 871211 ^z
  23.  */
  24.  
  25. #include <MacTypes.h>
  26. #include <FileMgr.h>
  27. #include <OSUtil.h>
  28. #include <HyperXCmd.h>
  29. #include <proto.h>
  30.  
  31. #define KEY_LENGTH  28            /* default choice in building indices */
  32. typedef struct
  33.   {
  34.     char kkey[KEY_LENGTH];
  35.     long ccount;
  36.   }  KEY_REC;
  37.  
  38.  
  39. pascal void main (XCmdBlockPtr paramPtr);
  40. void getKeyRec (KEY_REC *recp, long recNum, int refNum);
  41. int putNum (char *ans, long count);
  42. void complain (XCmdBlockPtr paramPtr);
  43. void init_target (KEY_REC *target, char *inputTarget);
  44. int zstrcmp (char *s1, char *s2);
  45.  
  46. pascal void main (paramPtr)
  47.   XCmdBlockPtr paramPtr;
  48.   {
  49.     KEY_REC thisRec, targetRec;
  50.     int refNum, diff, i;
  51.     long thisRecNum, maxRecNum, low, high;
  52.     Handle answer;
  53.     
  54.     if (paramPtr->paramCount != 3)
  55.       {
  56.           complain (paramPtr);
  57.           return;
  58.       }
  59.      
  60.     init_target (&targetRec, *(paramPtr->params[0]));
  61.     maxRecNum = atol (*(paramPtr->params[1]));
  62.     refNum = atol (*(paramPtr->params[2]));
  63.     
  64.     if (targetRec.kkey[0] == ' ' || refNum == 0)
  65.       {
  66.           complain (paramPtr);
  67.           return;
  68.       }
  69.     
  70.     low = 0;
  71.     high = maxRecNum;
  72.  
  73.     while (low <= high)
  74.       {
  75.         thisRecNum = (low + high) / 2;
  76.         getKeyRec (&thisRec, thisRecNum, refNum);
  77.         diff = zstrcmp (targetRec.kkey, thisRec.kkey);
  78.         if (diff < 0)
  79.             high = thisRecNum - 1;
  80.         else if (diff > 0)
  81.             low = thisRecNum + 1;
  82.         else
  83.           break;
  84.       }
  85.  
  86.     if (diff < 0)
  87.         --thisRecNum;
  88.     if (thisRecNum < 0)
  89.         thisRecNum = 0;
  90.     if (diff != 0)
  91.         SysBeep (10);
  92.     
  93.     answer = NewHandle (16);
  94.     i = putNum (*answer, thisRecNum);
  95.     *(*answer + i) = '\0';
  96.     paramPtr->returnValue = answer;
  97.     return;
  98.   }
  99.  
  100.  
  101. /* function to fetch the requested index record from the file ...
  102.  * note that if an illegal recNum is asked for, it
  103.  * returns 0 for ccount and a blank kkey....
  104.  */
  105.  
  106. void getKeyRec (recp, recordNum, refNum)
  107.   KEY_REC *recp;
  108.   long recordNum;
  109.   int refNum;
  110.   {
  111.     long count;
  112.     int i;
  113.  
  114.     count = sizeof(KEY_REC);
  115.             
  116.     if (recordNum < 0 ||
  117.             SetFPos (refNum, fsFromStart, 
  118.                     recordNum * sizeof(KEY_REC)) != noErr ||
  119.             FSRead (refNum, &count, recp) != noErr)
  120.       {
  121.         for (i = 0; i < KEY_LENGTH; ++i)
  122.             recp->kkey[i] = ' ';
  123.           recp->ccount = 0;
  124.       }
  125.  
  126.     return;
  127.   }
  128.  
  129.  
  130.  
  131. /* function to convert a number into a string and put it into the chosen
  132.  * target place ... returns the number of characters stored ...
  133.  * based on K&R p. 60 example of itoa()....
  134.  */
  135.  
  136. int putNum (ans, num)
  137.   char *ans;
  138.   long num;
  139.   {
  140.     int i, j, s, result;
  141.     
  142.     i = 0;
  143.     s = 1;
  144.     if (num < 0)
  145.       {
  146.         num = -num;
  147.         s = -1;
  148.       }
  149.     
  150.     do
  151.           ans[i++] = num % 10 + '0';
  152.     while ((num /= 10) > 0);
  153.     
  154.     if (s < 0)
  155.         ans[i++] = '-';
  156.     result = i;
  157.     
  158.     for (--i, j = 0; j < i; ++j, --i)
  159.       {
  160.           s = ans[i];
  161.           ans[i] = ans[j];
  162.           ans[j] = s;
  163.       }
  164.  
  165.     return (result);
  166.   }
  167.   
  168.  
  169. /* function to beep and set the return string to null (= "")
  170.  */
  171.  
  172. void complain (paramPtr)
  173.   XCmdBlockPtr paramPtr;
  174.   {
  175.     Handle answer;
  176.     
  177.       SysBeep (10);
  178.     answer = NewHandle (1);
  179.     **answer = '\0';
  180.     paramPtr->returnValue = answer;
  181.     return;
  182.   }
  183.  
  184.  
  185.  
  186. /* function to convert alphabetic string to a long integer ... from LSC
  187.  * library.... simplified to avoid using isspace() & isdigit() ....
  188.  */
  189.  
  190. long atol (s)
  191.   register char *s;
  192.   {
  193.     register char signflag = 0;
  194.     register long r = 0;
  195.  
  196.     while ((*s == ' '))
  197.         s++;
  198.         
  199.     if (*s == '-')
  200.       {
  201.         signflag = 1;
  202.         s++;
  203.       }
  204.     else if (*s == '+')
  205.          s++;
  206.  
  207.     while (*s >= '0' && *s <= '9') 
  208.         r = r * 10 + (*s++ - '0');
  209.     
  210.     return (signflag ? -r : r);
  211. }
  212.  
  213.  
  214. /* function to initialize the target key record kkey string ... turn the
  215.  * input target string (0-delimited) into all caps and pad to length
  216.  * KEY_LENGTH with blanks....
  217.  */
  218.  
  219. void init_target (target, inputTarget)
  220.   KEY_REC *target;
  221.   char *inputTarget;
  222.   {
  223.     register int i, c;
  224.     
  225.     for (i = 0; i < KEY_LENGTH; ++i)
  226.       {
  227.         c = inputTarget[i];
  228.         if (c == '\0')
  229.             break;
  230.         if (c >= 'a' && c <= 'z')
  231.             c += 'A' - 'a';
  232.         target->kkey[i] = c;
  233.       }
  234.     
  235.     for ( ; i < KEY_LENGTH; ++i)
  236.         target->kkey[i] = ' ';
  237.   }
  238.  
  239.  
  240. /* my function to compare two strings and give a result as to who is
  241.  * alphabetically earlier.  Note that this is almost the same as strncmp()
  242.  * with the fixed value of KEY_LENGTH as the maximum comparison distance,
  243.  * except that I must be sure to mask the characters to make them positive
  244.  * (since we want to be able to handle the non-ASCII funny letters in
  245.  * the Apple character set properly/consistently).  If the masking isn't
  246.  * done, then inconsistent results can occur with those non-ASCII chars!
  247.  */
  248.  
  249. int zstrcmp (s1, s2)
  250.   register char *s1, *s2;
  251.   {
  252.     register int n = KEY_LENGTH;
  253.     
  254.     for ( ; --n && ((*s1 & 0xFF) == (*s2 & 0xFF)); s1++, s2++)
  255.         if (!*s1) break;
  256.         
  257.     return ((*s1 & 0xFF) - (*s2 & 0xFF));
  258.   }
  259.  
  260.  
  261.  
  262.  
  263.